package com.ruike.alisurface.Serials.outGoods;

import android.os.Handler;
import android.os.Looper;
import android.os.SystemClock;

import com.ruike.alisurface.Serials.SerialPortInstructUtils;
import com.ruike.alisurface.Serials.Ttys3Utils;
import com.ruike.alisurface.utils.MyCountDownTimer;
import com.voodoo.lib_databases.annotation.Transient;
import com.voodoo.lib_utils.L;

/**
 * Author: voodoo
 * CreateDate: 2020-03-26 026 上午 10:39
 * Description: 升降机的工具类
 */
public class ShengJiangJiUtils {

    @Transient
    static MyCountDownTimer jlmCountDownTimer; // 卷帘门的倒计时
    static MyCountDownTimer qhmCountDownTimer; // 取货门的倒计时

    static boolean isInit = false; // 是否需要初始化
    static boolean isTurn = false; // 是否旋转了货道
    static boolean isNeedOutgoods = false; // 是需要出货
    static boolean isDouDong = false; // 是否抖动
    static boolean isHasStock = false; // 有无掉货
    static boolean isClosingDoor = false; // 正在关取货门
    static int mslotIndex; // 出货货道号
    static int mslotType; // 出货货道类型
    // 出货步骤，从转动出货并且抖动完之后开始计算
    static int outGoodsStep = 1; // 1、下降到出货口 2、关卷帘门 3、开取货们

    static final int ONE = 470;
    static final int TWO = 390;
    static final int THREE = 330;
    static final int FOUR = 240;
    static final int FIVE = 156;
    static final int SIX = 80;

    static final int out_windows = 220; // 出货口位置

    static int backStep = 0; // 升降机出货移动的步数
    static long toSlotTime; // 移动货道所需时间

    public static void initListener() {
        Ttys3Utils.getInstance().setOnSerialPortResultDataListener(new Ttys3Utils.OnSerialPortResultDataListener() {
            @Override
            public void serialPortResultData(String serialPortData, byte[] resultBytes) {
                Handler mainHandler = new Handler(Looper.getMainLooper());
                mainHandler.post(new Runnable() {
                    @Override
                    public void run() {
                        mySerialPortResultData(serialPortData, resultBytes);
                    }
                });
            }
        });
    }

    public static void init() {
        isInit = true;
        // 1、查询限位开关
        selectSwitch();
    }

    /**
     * 出货
     *
     * @param slotIndex 货道号
     * @param slotType  货道类型
     */
    public static void outGoods(int slotIndex, int slotType) {
        resetStatus();
        mslotIndex = slotIndex;
        mslotType = slotType;
        stopAllMotorRun();
        // 通知升降机开始买货
        L.iTag("出货流程", "1、停止所有电机的运行状态，通知单片机开始买货");
        Ttys3Utils.getInstance().SendPort(SerialPortInstructUtils.startShoping());
        switch (slotType) {
            case 0:
            case 21001: // 应该是后台返回的货道类型，兼容之前写好的所以加这么一个条件病转换到串口
                mslotType = 0;
                L.i("弹簧货道");
                break;
            case 1:
            case 21003:
                mslotType = 1;
                L.i("电磁锁货道");
                break;
            case 2:
            case 21002:
                mslotType = 2;
                L.i("履带货道");
                break;
            default:
                L.e("未知的货道类型 " + slotType);
                break;
        }

        if (slotIndex <= 0) {
            L.e("货道号异常 " + slotIndex);
            return;
        }

    }


    public static void mySerialPortResultData(String serialPortData, byte[] resultBytes) {

        if (isInit) { // 初始化
            if (resultBytes[0] == 0x01) { // 升降机通讯协议返回
                // 01 09 2D 00 14 03 01 14 03 01 67
                if (resultBytes[2] == 0x2D) { // 单片机接收到开机通讯指令
                    L.i("开启通讯成功！");
                    return;
                }
                // 限位开关返回状态
                if (resultBytes[2] == 0x3E) {
                    if (resultBytes[3] == 0x01) { // 在上限位
                        lifts(true, 500, true); // 向下运动
                    } else { // 在下限位或在中间位置
                        lifts(true, 500, false); // 向上运动
                    }
                }
                // 升降台运行中返回限位信息
                if (resultBytes[2] == 0x27) { // 升降台触碰到下限位开关
                    lifts(false, 0, false);
                    isInit = false;
                    if (onmSJJInitListener != null) {
                        onmSJJInitListener.initSuccess();
                    }
                } else if (resultBytes[2] == 0x28) { // 升降台触碰到上限位开关
//                    stopAllMotorRun();
                    lifts(false, 0, false);
                    SystemClock.sleep(500);
                    lifts(true, 500, true); // 向下运动
                }
            }
        } else { // 出货逻辑
            if (resultBytes[0] == 0x01) { // 升降机通讯协议返回
                if (resultBytes[2] == 0x2F) { // 单片机接收到安卓开机通知开始买货返回
                    L.iTag("出货流程", "2、单片机收到开始买货返回 " + serialPortData);
//                    stopAllMotorRun();
                    L.iTag("出货流程", "3、查询限位开关");
                    selectSwitch();
                }
                if (resultBytes[2] == 0x3E) { // 收到查询限位开关状态
                    L.iTag("出货流程", "4、收到查询限位开关返回 " + serialPortData);
                    if (resultBytes[3] == 0x01 || (resultBytes[3] == 0x00 && resultBytes[4] == 0x00)) { // 在上限位或者在中间
                        L.iTag("出货流程", "4-1、升降台在上限位或中间，向下运动");
                        lifts(true, 500, true); // 向下运动
                        isNeedOutgoods = true;
                    } else { // 在下限位
                        L.iTag("出货流程", "4-2、升降台在下限位，直接运动到" + mslotIndex + "货道出货");
                        moveToSlotOutGoods(mslotIndex);
                    }
                }
                // 升降台运行中返回限位信息
                if (resultBytes[2] == 0x27) { // 升降台触碰到下限位开关
                    L.iTag("出货流程", "升降运动中碰到下限位，停止电机转动");
                    lifts(false, 0, false);
                    SystemClock.sleep(500);
                    if (isNeedOutgoods) {
                        L.iTag("出货流程", "4-1-1、碰到下限位，需要出货，移动到货道层数");
                        isNeedOutgoods = false;
                        moveToSlotOutGoods(mslotIndex);
                    } else { // 不需要出货了，碰到下限位只是单纯判断货道出货结果给回调
                        L.iTag("出货流程", "10、升降台碰到下限位，不需要出货，返回出货结果");
                        if (isTurn && isHasStock) {
                            L.iTag("出货流程", "10-1、出货成功");
                            if (onmSJJOutGoodsListener != null) {
                                onmSJJOutGoodsListener.outGoodsSuccess();
                            }
                        } else {
                            L.iTag("出货流程", "出货失败 -- " + (!isTurn ? "货道" + mslotIndex + "电机未转动" : "未检测到掉货，货道：" + mslotIndex));
                            if (onmSJJOutGoodsListener != null) {
                                onmSJJOutGoodsListener.outGoodsFailure(!isTurn ? "货道" + mslotIndex + "电机未转动" : "未检测到掉货");
                            }
                        }
                    }
                } else if (resultBytes[2] == 0x28) { // 升降台触碰到上限位开关
                    L.iTag("出货流程", "4-1-2、升降运动中碰到上限位，停止电机转动，延时并向下运动");
                    lifts(false, 0, false);
                    SystemClock.sleep(500);
//                    stopAllMotorRun();
                    lifts(true, 500, true); // 向下运动
                }

                // 升降台步数移动完成 01 03 04 00 08
                if (resultBytes[2] == 0x04 || serialPortData.equals("01 03 04 00 08")) {
                    L.iTag("出货流程", "5、移动步数完成，停止电机转动，并延迟");
                    lifts(false, 0, false);
                    SystemClock.sleep(500);
//                    stopAllMotorRun(); // 停止所有电机运动
                    if (isDouDong) {
                        L.iTag("出货流程", "8、移动步数完成，正在抖动，则向上抖动25步");
                        isDouDong = false;
                        outGoodsStep = 1;
                        lifts(true, 25, false);
                    } else {
                        if (isTurn) {
                            if (isHasStock) { // 如果有掉货
                                L.eTag("出货流程", "9、转动过出货货到，并且有掉货");
                                if (outGoodsStep == 1) {
                                    L.eTag("出货流程", "9-1、移动到出货门");
                                    outGoodsStep = 2;
                                    lifts(true, Math.abs(backStep - out_windows), backStep - out_windows > 0);
                                } else if (outGoodsStep == 2) {
                                    L.eTag("出货流程", "9-2、关闭卷帘门");
                                    outGoodsStep = 3;
                                    juanLianDoor(false, false);
                                } else if (outGoodsStep == 3) {
                                    L.eTag("出货流程", "9-3、打开取货门");
                                    outGoodsStep = 4;
                                    outGoodsDoor(true, 200, true);
                                } else if (outGoodsStep == 4) { // 取货门打开并等待一段时间了
                                    L.eTag("出货流程", "9-4、取货门打开并等待一段时间了，关闭取货门");
                                    outGoodsStep = -1; // 此时步骤不再让任何方法进入，只在取货门上升到上限为的时候置为5
                                    isClosingDoor = true;
                                    outGoodsDoor(true, 200, false);
                                } else if (outGoodsStep == 5) { // 升降台回到最底部
                                    L.eTag("出货流程", "9-5、取货门碰到上限位开关，将卷帘门打开");
                                    outGoodsStep = 6;
                                    juanLianDoor(true, false);
                                } else if (outGoodsStep == 6) { // 升降台回到最底部
                                    L.eTag("出货流程", "9-6、卷帘门打开完成，将升降台移动到底部");
                                    lifts(true, out_windows, true);
                                    isNeedOutgoods = false;
                                }
                            } else {
                                L.eTag("未掉货，升降台直接移动到底部，并返回出货失败");
                                lifts(true, backStep + 10, true);
                            }
                        } else {
                            L.iTag("出货流程", "6、没有转动过出货电机，开始转动货道出货" + mslotIndex);
                            turnSlot(mslotIndex);
                        }
                    }
                }
                // 调货检测回传 01 02 0F 12
                if (resultBytes[2] == 0x0F) {
                    L.iTag("出货流程", "7-1、检测到掉货");
                    isHasStock = true;
                }
                // 取货门碰到上限位开关 01 02 3F 42
                if (resultBytes[2] == 0x3F) {
                    isClosingDoor = false;
                    L.eTag("出货步骤", "9-4-3、取货门碰到上限位，停止取货门并模拟回调步数完成动作 01 03 04 00 08");
                    outGoodsDoor(false, 0, false);
//                    stopAllMotorRun();
                    outGoodsStep = 5; // 第5步，打开卷帘门
                    mySerialPortResultData("01 03 04 00 08", new byte[]{0x01, 0x03, 0x04, 0x00, 0x08});
                }
                // 取货门碰到下限位开关 01 02 40 43
                if (resultBytes[2] == 0x40) {
                    if (!isClosingDoor) {
                        outGoodsDoor(false, 0, false);
                        if (qhmCountDownTimer != null) {
                            qhmCountDownTimer.cancel();
                        }
                        qhmCountDownTimer = new MyCountDownTimer(7 * 1000, 1000) {
                            @Override
                            public void onTick(long millisUntilFinished) {
                                L.iTag("出货流程", "9-3-2、等待取货倒计时：" + millisUntilFinished / 1000 + 1);
                            }

                            @Override
                            public void onFinish() {
                                L.iTag("出货流程", "9-3-3、取货门到下限位并延迟5秒钟，延迟完成，模拟给回调发送步数完成发的指令 01 03 04 00 08");
                                mySerialPortResultData("01 03 04 00 08", new byte[]{0x01, 0x03, 0x04, 0x00, 0x08});
                            }
                        }.start();
                    }
                }
                // 取货门中有手 01 02 1B 1E
                if (resultBytes[2] == 0x1B) {
                    if (isClosingDoor) {
                        L.iTag("出货流程", "9-4-1、门中有手，停止取货门电机并向下开门");
                        outGoodsDoor(false, 0, false);
                        SystemClock.sleep(500);
                        outGoodsDoor(true, 10, true);
                    }
                }
                // 取货门中无手 01 02 1C 1F
                if (resultBytes[2] == 0x1C) {
                    if (isClosingDoor) {
                        L.iTag("出货流程", "9-4-2、门中无手，停止取货门电机并关门");
                        outGoodsDoor(false, 0, false);
                        SystemClock.sleep(500);
                        outGoodsDoor(true, 200, false);
                    }
                }
            }
//            驱动板指令回调 10 0E 02 04 01 0C 00 01 13 0B 1D 13 0C 05 20 B1
            if (resultBytes[0] == 0x10) {
                if (resultBytes[2] == 0x02) { // 驱动板指令出货完成返回
                    L.iTag("出货流程", "7、转动出货电机完成，开始抖动，升降台向下移动25步");
                    isTurn = true;
                    isDouDong = true;
                    lifts(false, 0, false);
                    SystemClock.sleep(500);
                    lifts(true, 25, true);
                }
            }
        }

    }

    /**
     * 重置所有状态
     */
    private static void resetStatus() {
        isInit = false; // 是否需要初始化
        isTurn = false; // 是否旋转了货道
        isNeedOutgoods = false; // 是需要出货
        isDouDong = false; // 是否抖动
        isHasStock = false; // 有无掉货
        isClosingDoor = false; // 正在关取货门
        mslotIndex = 0; // 出货货道号
        mslotType = 0; // 出货货道类型
        // 出货步骤，从转动出货并且抖动完之后开始计算
        outGoodsStep = 1; // 1、下降到出货口 2、关卷帘门 3、开取货们
    }

    /**
     * 停止所有电机的运动
     */
    private static void stopAllMotorRun() {
        SystemClock.sleep(500);
        Ttys3Utils.getInstance().SendPort(SerialPortInstructUtils.sjjControlMotor(1, false, 70, 500, false));
        SystemClock.sleep(500);
        Ttys3Utils.getInstance().SendPort(SerialPortInstructUtils.sjjControlMotor(4, false, 60, 100, false));
        SystemClock.sleep(500);
        Ttys3Utils.getInstance().SendPort(SerialPortInstructUtils.sjjControlMotor(5, false, 60, 500, false));
        SystemClock.sleep(500);
    }

    // ==================================================================================
    // ===                         结果回调接口给UI线程用
    // ==================================================================================

    public static OnSJJInitListener onmSJJInitListener;
    public static OnSJJOutGoodsListener onmSJJOutGoodsListener;

    public static void setOnSJJListener(OnSJJInitListener onSJJInitListener) {
        onmSJJInitListener = onSJJInitListener;
    }

    public static void setOnSJJListener(OnSJJOutGoodsListener onSJJOutGoodsListener) {
        onmSJJOutGoodsListener = onSJJOutGoodsListener;
    }

    // 初始化结果接口回调
    public interface OnSJJInitListener {
        void initSuccess();

        void initFailure();
    }

    // 出货结果接口回调
    public interface OnSJJOutGoodsListener {
        void outGoodsSuccess();

        void outGoodsFailure(String msg);
    }

    // ==================================================================================
    // ===                              发送各种指令
    // ==================================================================================

    /**
     * 查询限位
     */
    private static void selectSwitch() {
//        stopAllMotorRun();
        Ttys3Utils.getInstance().SendPort(SerialPortInstructUtils.selectSwitch());
    }

    /**
     * 升降台运动
     *
     * @param isTurn     是否转动
     * @param stepNumber 运动步数
     * @param isMoveDown 向下运动
     */
    private static void lifts(boolean isTurn, int stepNumber, boolean isMoveDown) {
        Ttys3Utils.getInstance().SendPort(SerialPortInstructUtils.sjjControlMotor(1, isTurn, 70, stepNumber, isMoveDown));
    }

    /**
     * 取货门运动
     *
     * @param isTurn     是否转动
     * @param stepNumber 运转步数
     * @param isOpen     开门
     */
    private static void outGoodsDoor(boolean isTurn, int stepNumber, boolean isOpen) {
        Ttys3Utils.getInstance().SendPort(SerialPortInstructUtils.sjjControlMotor(5, isTurn, 70, stepNumber, isOpen));
    }

    /**
     * 升降台移动到货道
     *
     * @param slotIndex 货道号
     */
    private static void moveToSlotOutGoods(int slotIndex) {
        if (slotIndex >= 1 && slotIndex < 10) {
            L.i("上升到第一层");
            lifts(true, ONE, false);
            backStep = ONE;
            toSlotTime = 20000;
        }
        if (slotIndex >= 10 && slotIndex < 20) {
            L.i("上升到第二层");
            lifts(true, TWO, false);
            backStep = TWO;
            toSlotTime = 18000;
        }
        if (slotIndex >= 20 && slotIndex < 30) {
            L.i("上升到第三层");
            lifts(true, THREE, false);
            backStep = THREE;
            toSlotTime = 16000;
        }
        if (slotIndex >= 30 && slotIndex < 40) {
            L.i("上升到第四层");
            lifts(true, FOUR, false);
            backStep = FOUR;
            toSlotTime = 14000;
        }
        if (slotIndex >= 40 && slotIndex < 50) {
            L.i("上升到第五层");
            lifts(true, FIVE, false);
            backStep = FIVE;
            toSlotTime = 12000;
        }
        if (slotIndex >= 50 && slotIndex < 60) {
            L.i("上升到第六层");
            lifts(true, SIX, false);
            backStep = SIX;
            toSlotTime = 10000;
        }
    }

    /**
     * 转动货道
     *
     * @param slotIndex 货道号
     */
    private static void turnSlot(int slotIndex) {
        Ttys3Utils.getInstance().SendPort(SerialPortInstructUtils.quDongOutGoods(slotIndex, 0));
    }

    /**
     * 卷帘门开关
     *
     * @param isOpen 开门 true:开 false:关
     * @param isTest 是否是测试界面点击的
     */
    public static void juanLianDoor(boolean isOpen, boolean isTest) {
        L.iTag("出货流程", (isOpen ? "开启" : "9-2-1、关闭") + "卷帘门");
        Ttys3Utils.getInstance().SendPort(
                SerialPortInstructUtils.sjjControlMotor(4, true, 60, 100, !isOpen));
        if (jlmCountDownTimer != null) {
            jlmCountDownTimer.cancel();
        }
        jlmCountDownTimer = new MyCountDownTimer(5300, 100) {
            @Override
            public void onTick(long millisUntilFinished) {
                L.iTag("倒计时", "卷帘门:" + millisUntilFinished / 100);
            }

            @Override
            public void onFinish() {
                L.iTag("出货流程", "9-2-2、计时完毕，停止卷帘门动作！");
                Ttys3Utils.getInstance().SendPort(
                        SerialPortInstructUtils.sjjControlMotor(4, false, 60, 100, !isOpen));
                SystemClock.sleep(500);
                if (!isTest) { // 如果是测试界面点击的则不模拟返回该指令
                    // 模拟给回调方法一个步数完成的指令，表示卷帘门电机运行步数完成
                    L.iTag("出货流程", "9-2-3、给模拟回调发送步数移动完成的指令:01 03 04 00 08");
                    mySerialPortResultData("01 03 04 00 08", new byte[]{0x01, 0x03, 0x04, 0x00, 0x08});
                }
            }
        }.start();
    }

}
